/************************* File Information ****************************
 * Copyright(C): This is my company secrecy java source code. Any copy or change
 * from this file must agreed by my company.
 *
 ************************* History **********************************
 * Create: zhou.h.m,  Date: 2009-8-5.
 * Create Description
 *
 *  $Id$
 *
 ************************* To  Do ***********************************
 *
 ************************* Others ***********************************
 * Add anything you want to write here.
 * 
 * 
 ******************************************************************
 */
package sac.xsd.comm;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Vector;

import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;

import sac.utility.Common;
import cldc.xsd.parse.IPacket;
import cldc.xsd.parse.SeqidPacket;

/**
 * @author zhou.h.m
 */
public abstract class HttpClient extends Thread {
		
	boolean running;
	
	String webUrl;
	
	public final static String CNWAP_PROXY_IP = "10.0.0.172";
	
	String proxyURL = null;
	
	private String cookies = null;
	
	Object responseSync = new Object();
	Vector requests = new Vector();
	String responseText;
	
	int timeout = 1500000;	//15 seconds to timeout.
	
	public HttpClient(String webUrl) {
		this.webUrl = webUrl;
		this.running = true;
		this.start();
	}
	
	/**
	 * stop thread working.
	 *
	 */
	public void stopWorking() {
		running = false;
		synchronized (requests) {
			requests.notifyAll();
		}
		//this.interrupt();
	}
	
	private HttpConnection openConnection() throws IOException {
		if (proxyURL == null) {
			 return (HttpConnection) Connector.open(webUrl);
		} else {
			int startIndex = "http://".length();
			int endIndex = webUrl.indexOf("/", startIndex + 1);
			String tempURL = "http://" + proxyURL + webUrl.substring(endIndex);
			String root = webUrl.substring(startIndex, endIndex);
			
			HttpConnection httpConn = (HttpConnection) Connector.open(tempURL);
			httpConn.setRequestProperty("X-Online-Host", root);

			return httpConn;
		}
	}
	
	//only can called by one thread.
	public String invokePacket(IPacket packet) {
		
		synchronized (requests) {
			responseText = null;
			requests.addElement(packet);
			requests.notify();
		}
		
		synchronized (responseSync) {
			if (responseText != null) {
				return responseText;
			}
			try {
				responseSync.wait(timeout);
			} catch (InterruptedException exp) {
				return null;
			}
			return responseText;
		}
	}
	
	// get the sequence id.
	private static int seqId = 1;
	//private static Object seqIdSync = new Object();
	
	public static int getSeqId() {
	//	synchronized (seqIdSync) {
			return seqId++;		//This running by single thread, doesn't need synchronized.
	//	}
	}
	
	public IPacket invokeRequest(SeqidPacket request) {
		request.setSeqId(getSeqId());
		String text = invokePacket(request);
		
		try {
			return parse(text);
		} catch (Exception exp) {
			WebServerError error = new WebServerError();
			error.setSeqId(request.getSeqId());
			error.setResult(text);
			
			return error;
		}
	}
	
	private void getCookies(HttpConnection httpConn) {
		try {
			String tempcookies = httpConn.getHeaderField("Set-Cookie");
			if (tempcookies != null && tempcookies.length() > 0) {
				int index = tempcookies.indexOf(";");
				if (index > 0) {
					cookies = tempcookies.substring(0, index);
				} else {
					cookies = tempcookies;
				}
				System.out.println("Set the cookies to: " + cookies);
			}
		} catch (IOException e) {
		}
	}
	
	/**
	 * encode the packet to string.
	 * @param packet
	 */
	abstract public String encode(IPacket packet);
	abstract public IPacket parse(String text) throws Exception;
	
	
	public static void closeInput(InputStream is) {
		try {
			if (is != null) {
				is.close();
			}
		} catch (IOException e) {
			;
		}
	}

	public static void closeOutput(OutputStream os) {
		try {
			if (os != null) {
				os.close();
			}
		} catch (IOException e) {
		} finally {
			os = null;
		}
	}

	public static void closeHttpConn(HttpConnection httpConn) {
		try {
			if (httpConn != null) {
				httpConn.close();
			}
		} catch (IOException e) {
			;
		}
	}
	
	private static byte[] getNetData(InputStream is) {
		int connectionDownloadData = 0;
		int totalReceiveDate = 0;
		int DATASIZE = 1024;
		byte[] tempData = new byte[DATASIZE];
		byte[] realData = new byte[10280];
		int length = 0;
		boolean successed = false;
		try {
			length = is.read(tempData);
			while (length != -1) {
				connectionDownloadData += length;
				System.arraycopy(tempData, 0, realData, totalReceiveDate, length);
				totalReceiveDate += length;
				if (totalReceiveDate >= (realData.length - DATASIZE)) {
					byte[] temp = new byte[realData.length + DATASIZE * 2];
					System.arraycopy(realData, 0, temp, 0, totalReceiveDate);
					realData = temp;
				}

				length = is.read(tempData);
			}
			successed = true;
		} catch (Throwable e1) {
			e1.printStackTrace();
		} finally {

		}
		byte[] messageData = null;
		if (successed && totalReceiveDate > 0) {
			messageData = new byte[totalReceiveDate];
			System.arraycopy(realData, 0, messageData, 0, totalReceiveDate);
		}
		return messageData;
	}
	
	public void run() {
		while (running) {
			
			//define the input and output stream.
			HttpConnection httpConn = null;
			OutputStream os = null;
			InputStream is = null;
			
			//send it.
			try {
				
				//get the packet from the hash table.
				IPacket packet = null;
				synchronized (requests) {
					if (requests.size() == 0) {
						requests.wait();
					}
					if (requests.size() > 0) {
						packet = (IPacket)requests.elementAt(0);
						requests.removeElementAt(0);
					}
				}
				
			
				//send the packet
				if (packet != null) {
					String text = encode(packet);
					
					httpConn = openConnection();
					
					if (cookies != null) {
						httpConn.setRequestProperty("Cookie", cookies);
					}
					
					//post the content.
					httpConn.setRequestMethod(HttpConnection.POST);
					httpConn.setRequestProperty("Connection", "Keep-Alive");
					httpConn.setRequestProperty("Pragma", "no-cache");
					httpConn.setRequestProperty("Content-Type", "text/html; charset=UTF-8");
					
					byte[] contents = text.getBytes("UTF-8");
					
					httpConn.setRequestProperty("Content-Length", contents.length + "");
					
					os = httpConn.openDataOutputStream();
					os.write(contents);
			
					is = httpConn.openDataInputStream();
					String response = new String(getNetData(is), Common.ENCODE_CHAR);
					
					//set the cookies.
					getCookies(httpConn);
					
					//get the cookie.
					synchronized (responseSync) {
						responseText = response;
						responseSync.notify();
					}
				}
			} catch (Exception exp) {
				exp.printStackTrace();
			} finally {
				if (httpConn != null) {
					closeInput(is);
					closeOutput(os);
					closeHttpConn(httpConn);
				}
			}
		}
	}

	/** @return Returns the proxyURL.
	 */
	public String getProxyURL() {
		return proxyURL;
	}

	/** @param proxyURL The proxyURL to set.
	 */
	public void setProxyURL(String proxyURL) {
		this.proxyURL = proxyURL;
	}
}
